package proyecto.testcasetool.presentation.actions;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.List;

import org.apache.commons.lang3.StringEscapeUtils;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.ui.dialogs.DiagnosticDialog;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.domain.IEditingDomainProvider;
import org.eclipse.emf.edit.provider.IItemLabelProvider;
import org.eclipse.emf.edit.ui.EMFEditUIPlugin;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.window.Window;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;

import proyecto.testcasetool.Subject;
import proyecto.testcasetool.UseCase;
import proyecto.testcasetool.UseCaseModel;
import proyecto.testcasetool.presentation.editor.TestcasetoolEditor;
import proyecto.testcasetool.presentation.editor.TestcasetoolEditorPlugin;
import testcasetool.transformation.algorithm.Ad2TestCase;
import testcasetool.transformation.algorithm.Uc2AdTransformation;
import testcasetool.transformation.presentation.TestCaseHtmlViewer;
import testcasetool.transformation.presentation.UseCaseHtmlViewer;
import testcasetool.transformation.uml.activity.Activity;
import testcasetool.transformation.uml.utp.TestCase_TestCase;

public class GenerateTestCaseAction extends Action {

	private static final String USE_CASE_FILE_PREFIX = "Use-Case-";
	private static final String TESTCASES = "testcases";
	protected EditingDomain domain;
	protected StringBuffer indexHtml;

	public GenerateTestCaseAction() {
		setToolTipText("Generate Test Cases");
		setImageDescriptor(ImageDescriptor
				.createFromURL((URL) TestcasetoolEditorPlugin.getPlugin()
						.getImage("16x16/Process.gif")));
	}

	@Override
	public void run() {

		IWorkbench wb = PlatformUI.getWorkbench();
		IWorkbenchWindow win = wb.getActiveWorkbenchWindow();
		IWorkbenchPage page = win.getActivePage();
		domain = ((IEditingDomainProvider) page.getActiveEditor())
				.getEditingDomain();

		page.saveEditor(page.getActiveEditor(), true);
		
		if (page.getActiveEditor().isDirty()){
			return;
		}
		
		UseCaseModel model = (UseCaseModel) domain.getResourceSet()
				.getResources().get(0).getContents().get(0);

		Diagnostician diag = createDiagnostician(((TestcasetoolEditor)page.getActiveEditor()).getAdapterFactory());
		Diagnostic diagnostic = diag.validate(model);
		handleDiagnostic(diagnostic);
		if (diagnostic.getSeverity() == diagnostic.ERROR){
			return;
		}
		
		
		
		// codigo para crear archivos dentro del proyecto
		IFileEditorInput input = (IFileEditorInput)page.getActiveEditor().getEditorInput();
		IFile file = input.getFile();
		IProject activeProject = file.getProject();
		
		// progress monitor por si demora mucho la ejecucion
		IProgressMonitor progressMonitor = new NullProgressMonitor();
		
		IFolder folder = generateTestCasesFolder(activeProject, progressMonitor, file.getParent().getProjectRelativePath().toString());
		
		initializeIndexHtml(model.getSubject());
		for (UseCase uc : model.getSubject().getUseCase()) {
			 addTestCaseFileToIndex(generateTestCaseHtmlForUseCase(progressMonitor, folder, uc), uc);
		}
		finalizeIndexHtml();
		createFile(progressMonitor, folder, "index.html", indexHtml);
		
		
		super.run();
	}

	private void finalizeIndexHtml() {
		indexHtml.append("\t\t</ol>");
		getHtmlFooter(indexHtml);		
	}

	private void initializeIndexHtml(Subject subject) {
		indexHtml = new StringBuffer();
		getHtmlHeader("Test Cases for " + subject.getName(), indexHtml);
		indexHtml.append("\t\t<h1>Test Cases for ");
		indexHtml.append(StringEscapeUtils.escapeHtml4(subject.getName()));
		indexHtml.append("</h1>\n");
		indexHtml.append("\t\t<h2>System Description</h2>\n");
		indexHtml.append("\t\t<p>");
		indexHtml.append(StringEscapeUtils.escapeHtml4(subject.getDescription()));
		indexHtml.append("\t\t</p>\n");
		
		indexHtml.append("\t\t<h2>Use Cases</h2>\n");
		indexHtml.append("\t\t<p>Below you'll find the list of Use Cases with its corresponding generated Test Cases</p>\n");
		indexHtml.append("\t\t<ol>");
		
	}

	private void getHtmlHeader(String htmlTitle, StringBuffer sb) {
		sb.append("<html>\n");
		sb.append("\t<head>\n");
		sb.append("\t\t<title>");
		sb.append(htmlTitle);
		sb.append("</title>\n");
		
		sb.append("\t\t<link href=\"http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css\" rel=\"stylesheet\">\n");
		sb.append("\t\t<script src=\"http://code.jquery.com/jquery-1.9.1.js\"></script>\n");
		sb.append("\t\t<script src=\"http://code.jquery.com/ui/1.10.3/jquery-ui.js\"></script>\n");
		sb.append("\t\t<style>");
		sb.append("\t\tbody{\n");
		sb.append("\t\t	font: 95% \"Trebuchet MS\", sans-serif;\n");
		sb.append("\t\t	margin: 50px;\n");
		sb.append("\t\t}\n");
		sb.append("\t\t</style>");

		sb.append("\t</head>\n");
		sb.append("\t<body>\n");
	}
	
	private void getHtmlFooter(StringBuffer sb) {
		sb.append("\t</body>\n");
		sb.append("</html>");
	}

	private void addTestCaseFileToIndex(String fileName, UseCase uc) {
		indexHtml.append("<li>");
		indexHtml.append(StringEscapeUtils.escapeHtml4(uc.getName()));
		indexHtml.append(" <ol start=\"1\" style=\"list-style-type: lower-roman;\">");
		indexHtml.append("<li><a href=\"Use-Case-");
		indexHtml.append(fileName);
		indexHtml.append("\">Use Case</li>");
		indexHtml.append("<li><a href=\"");
		indexHtml.append(fileName);
		indexHtml.append("\">Test Cases</li>");
		indexHtml.append("</ol>");
		indexHtml.append("</a></li>\n");
		
	}

	private String generateTestCaseHtmlForUseCase(IProgressMonitor progressMonitor, IFolder folder, UseCase uc) {
		String fileName = uc.getName().replaceAll(" ", "_") + ".html";
		Activity ad = Uc2AdTransformation.generateActivityDiagram(uc);
		List<TestCase_TestCase> testCases = Ad2TestCase.generateTestCases(ad);
		StringBuffer sb = new StringBuffer();
		getHtmlHeader("Generated Test Cases for " + uc.getName(), sb);
		sb.append("\n<script>" +
				"	$(function() { " +
				"		$( \"#accordion\" ).accordion({ " +
				"			heightStyle: \"content\", " +
				"			collapsible: true" +
				"		});" +
				"		$( document ).tooltip();" +
		//		"		$( \"a\" ).button();" +
				" 	});" +
				"</script>\n");
		appendNavigation(sb, "View Use Case", USE_CASE_FILE_PREFIX + fileName);
		sb.append("<h1>Generated Test Cases for <i>" + StringEscapeUtils.escapeHtml4(uc.getName()) + "</i></h1>\n");
		sb.append("<div id=\"accordion\">\n");
		for (TestCase_TestCase tc : testCases) {
			sb.append("<h3>" + StringEscapeUtils.escapeHtml4(tc.getName()) + "</h3>");
			sb.append("<div>\n");
			sb.append(TestCaseHtmlViewer.generateHtmlTestCase(tc));
			//sb.append("<HR />\n");
			sb.append("</div>\n");
		}
		sb.append("</div>\n");
		getHtmlFooter(sb);
		generateHtmlForUseCase(progressMonitor, folder, uc, fileName);
		return createFile(progressMonitor, folder, fileName, sb);
	}

	private void appendNavigation(StringBuffer sb, String label, String fileName) {
		sb.append("<table align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" style=\"width:100%\">\n");
		sb.append("		<tr>\n");
		sb.append("			<td>\n");
		sb.append("				<a href=\"index.html\">Return to Index</a>\n");
		sb.append("			</td>\n");
		sb.append("			<td style=\"text-align: right;\">\n");
		sb.append("				<a href=\"" + fileName + "\">" + label + "</a>\n");
		sb.append("			</td>\n");
		sb.append("		</tr>\n");
		sb.append("</table>\n");
	}
	
	private String generateHtmlForUseCase(IProgressMonitor progressMonitor, IFolder folder, UseCase uc, String fileName) {
		StringBuffer sb = new StringBuffer();
		getHtmlHeader("Use Case details for " + uc.getName(), sb);
		appendNavigation(sb, "View Test Cases", fileName);
		sb.append("<h1>Use Case details for <i>" + StringEscapeUtils.escapeHtml4(uc.getName()) + "</i></h1>\n");
		sb.append(UseCaseHtmlViewer.generateUseCaseHtmlTable(uc));
		getHtmlFooter(sb);
		
		return createFile(progressMonitor, folder, USE_CASE_FILE_PREFIX + fileName, sb);
	}

	private String createFile(IProgressMonitor progressMonitor, IFolder folder,
			String fileName, StringBuffer sb) {
		IFile newFile = folder.getFile(fileName);
		InputStream source = new ByteArrayInputStream(sb.toString().getBytes());

		try {
			newFile.create(source, false, progressMonitor);
			return fileName;
		} catch (CoreException e) {
			e.printStackTrace();
			return null;
		}
	}

	private IFolder generateTestCasesFolder(IProject activeProject,
			IProgressMonitor progressMonitor, String path) {
		// folder donde van a ir los archivos, se crea una sola vez
		IFolder folder = activeProject.getFolder(path+ "/" +TESTCASES);
		
		// si no existe se crea si ya existe se borra y se crea de nuevo
		try {
			if (!folder.exists()) {
				folder.create(IResource.NONE, true, progressMonitor);
			}
			else {
				folder.delete(true, progressMonitor);
				folder.create(IResource.NONE, true, progressMonitor);
			}
		} catch (CoreException e1) {
			e1.printStackTrace();
		}
		return folder;
	}

	
	protected void handleDiagnostic(Diagnostic diagnostic)
	  {
	    int severity = diagnostic.getSeverity();
	    String title = null;
	    String message = null;

	    if (severity == Diagnostic.ERROR || severity == Diagnostic.WARNING)
	    {
	      title = EMFEditUIPlugin.INSTANCE.getString("_UI_ValidationProblems_title");
	      message = EMFEditUIPlugin.INSTANCE.getString("_UI_ValidationProblems_message");
	    }
	    else
	    {
	      title = EMFEditUIPlugin.INSTANCE.getString("_UI_ValidationResults_title");
	      message = EMFEditUIPlugin.INSTANCE.getString(severity == Diagnostic.OK ? "_UI_ValidationOK_message" : "_UI_ValidationResults_message");
	    }

	    int result = 0;
	    if (diagnostic.getSeverity() == Diagnostic.OK)
	    {
	      //MessageDialog.openInformation(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), title, message);
	      result = Window.CANCEL;
	    }
	    else
	    {
	      result = DiagnosticDialog.open
	        (PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), title, message, diagnostic);
	    }
	    
	  }
	
	protected Diagnostician createDiagnostician(final AdapterFactory adapterFactory)
	  {
	    return 
	      new Diagnostician()
	      {
	        @Override
	        public String getObjectLabel(EObject eObject)
	        {
	          if (adapterFactory != null && !eObject.eIsProxy())
	          {
	            IItemLabelProvider itemLabelProvider = (IItemLabelProvider)adapterFactory.adapt(eObject, IItemLabelProvider.class);
	            if (itemLabelProvider != null)
	            {
	              return itemLabelProvider.getText(eObject);
	            }
	          }
	  
	          return super.getObjectLabel(eObject);
	        }
	      };
	  }
}
